package tt.dz.appserver.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.ResultSet;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.httpclient.util.DateUtil;

import com.alibaba.fastjson.JSON;

import tt.dz.appserver.entity.dto.push.ReservationDto;
import tt.dz.appserver.util.annotation.AnnotationUtils;

/**
 * 反射帮助类
 * 
 * @author 谢龙飞
 * 
 */
@SuppressWarnings("unchecked")
public final class ReflectUtils {

	/**
	 * 通过对象、属性名称和类调用Get方法
	 * 
	 * @param obj
	 *            对象
	 * @param fieldName
	 *            属性名称
	 * @param cls
	 *            类
	 * @return
	 */
	public static final Object invokeObjectReadMethodByFieldNameAndClass(
			Object obj, String fieldName, Class<?> cls) {

		PropertyDescriptor descriptor;
		try {
			descriptor = new PropertyDescriptor(fieldName, cls);
			// 得到get方法
			Method method = descriptor.getReadMethod();
			if (method == null) {
				return null;
			}
			// 调用
			return method.invoke(obj);
		} catch (IllegalAccessException | IllegalArgumentException
				| InvocationTargetException | IntrospectionException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 向属性中写入值（调用set方法）
	 * 
	 * @param obj
	 * @param fieldName
	 * @param cls
	 * @param fieldValue
	 * @return
	 */
	public static final boolean invokeObjectWriteMethodByFieldNameAndClass(
			Object obj, Field field, Class<?> cls, Object fieldObj) {

		PropertyDescriptor descriptor;
		try {
			descriptor = new PropertyDescriptor(field.getName(), cls);
			// 得到set方法
			Method method = descriptor.getWriteMethod();
			fieldObj += "";
			// 得到属性类型
			Class<?> typeName = field.getType();

			// 判断类型并调用set方法
			if (typeName.equals(Integer.class)) {
				Integer fieldValue = (Integer) fieldObj;
				method.invoke(obj, fieldValue);
			} else if (typeName.equals(Double.class)) {
				Double fieldValue = (Double) fieldObj;
				method.invoke(obj, fieldValue);
			} else if (typeName.equals(String.class)) {
				String fieldValue = (String) fieldObj;
				method.invoke(obj, fieldValue);
			} else if (typeName.equals(Short.class)) {
				Short fieldValue = (Short) fieldObj;
				method.invoke(obj, fieldValue);
			} else if (typeName.equals(Float.class)) {
				Float fieldValue = (Float) fieldObj;
				method.invoke(obj, fieldValue);
			}
			return true;
		} catch (IllegalAccessException | IllegalArgumentException
				| InvocationTargetException | IntrospectionException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 设置属性值
	 * 
	 * @param field
	 *            属性对象
	 * @param obj
	 *            设置对象
	 * @param rs
	 *            数据resultset
	 * @param cls
	 *            类
	 */
	public static final void setFieldsValue(Field field, ResultSet rs,
			Object obj, Class<?> cls) {

		try {
			Object fieldObj = rs.getObject(field.getName());
			if (fieldObj != null) {
				PropertyDescriptor descriptor = new PropertyDescriptor(
						field.getName(), cls);
				// 得到set方法
				Method method = descriptor.getWriteMethod();
				Class<?> fieldType = field.getType();
				if (fieldType.equals(Integer.class)) {
					Integer fieldValue = (Integer) fieldObj;
					method.invoke(obj, fieldValue);
				} else if (fieldType.equals(Double.class)) {
					Double fieldValue = (Double) fieldObj;
					method.invoke(obj, fieldValue);
				} else if (fieldType.equals(String.class)) {
					String fieldValue = (String) fieldObj;
					method.invoke(obj, fieldValue);
				} else if (fieldType.equals(Short.class)) {
					Short fieldValue = (Short) fieldObj;
					method.invoke(obj, fieldValue);
				} else if (fieldType.equals(Float.class)) {
					Float fieldValue = (Float) fieldObj;
					method.invoke(obj, fieldValue);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设置查询的列
	 * 
	 * @param fields
	 * @param tableName
	 * @param referenceTables
	 * @param referenceColumns
	 */
	public final static String setQueryColumn(final Field[] fields,
			final String tableName) {

		final StringBuffer sqlBuffer = new StringBuffer();

		// 设置查询的列（所有）
		for (Field field : fields) {
			if (!ReflectUtils.judgeModifiersAvailable(field)) {
				// 是否为忽略映射属性
				if (!AnnotationUtils.ignore(field)) {
					sqlBuffer.append(field.getName());
					sqlBuffer.append(',');
				}
			}
		}
		// 删除最后一个逗号
		sqlBuffer.deleteCharAt(sqlBuffer.length() - 1);
		return sqlBuffer.toString();
	}

	/**
	 * 通过修饰符判断属性是否可用
	 * 
	 * @param field
	 * @return
	 */
	public final static boolean judgeModifiersAvailable(final Field field) {

		int fieldModifier = field.getModifiers();

		return ((fieldModifier & Modifier.STATIC)
				| (fieldModifier & Modifier.FINAL)
				| (fieldModifier & Modifier.VOLATILE) 
				| (fieldModifier & Modifier.TRANSIENT)) != 0;

	}

	/**
	 * 转换map为对象
	 * 
	 * @param map
	 * @param cls
	 * @return
	 */
	public final static Object mapParseObjectOfClass(
			final Map<String, Object> map, final Class<?> cls) {

		Object obj = null;
		try {
			// 创建对象
			obj = cls.newInstance();
			// 获取属性
			final Field[] fields = cls.getDeclaredFields();

			for (Field field : fields) {

				String fileName = field.getName();

				// 判断map中的值
				if (map.containsKey(fileName)) {
					// 设置值
					field.setAccessible(true);
					field.set(obj, map.get(fileName));
				}
			}
		} catch (InstantiationException | IllegalAccessException
				| SecurityException | IllegalArgumentException e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	/**
	 * Map 表合并
	 * @param mainMap
	 * @param mergeMap
	 * @return
	 */
	public final static void mergeHashMap(Map<String,Object> mainMap, Map<String,Object>...mergeMap){
		
		//如果合并的map数组不为空
		if(mergeMap!=null){
			
			//开始循环合并的数组
			for (Map<String, Object> map : mergeMap) {
				
				if(map!=null){
					//取出所有的值然后存入主体map
					for (Iterator<String> iter = map.keySet().iterator();iter.hasNext();) {
						String key = iter.next();
						if(!mainMap.containsKey(key)){
							mainMap.put(key, map.get(key));
						}
					}
				}
			}
		}
	}
	/**
	 * 对象转Map
	 * @param obj
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public final static Map<String,String> objectParseMap(Object obj) throws IllegalArgumentException, IllegalAccessException{
		
		Map<String,String> resultMap = new HashMap<String,String>();
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field field : fields) {
			
			field.setAccessible(true);
			Object fieldValue = field.get(obj);
			if(fieldValue!=null){
				String key = field.getName();
				Class<?> typeClass = fieldValue.getClass();
				if(typeClass.equals(Date.class)){
					Date d = (Date) fieldValue;
					resultMap.put(key, DateUtil.formatDate(d));
				}
				else if(typeClass.equals(String.class)){
					String str = (String) fieldValue;
					resultMap.put(key, str);
				}
				else if(typeClass.equals(Float.class)){
					Float fl = (Float) fieldValue;
					resultMap.put(key, fl.toString());
				}
				else if(typeClass.equals(Double.class)){
					Double dou = (Double) fieldValue;
					resultMap.put(key, dou.toString());
				}
			}
		}
		return resultMap;
	}

	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
		
		Map<String,Object> m1 = new HashMap<String,Object>();
		Map<String,Object> m2 = new HashMap<String,Object>();
		Map<String,Object> m3 = new HashMap<String,Object>();
		Map<String,Object> m4 = new HashMap<String,Object>();
		System.out.println(m1);
		mergeHashMap(m1, m2, m3, m4);
		System.out.println(m1);
		ReservationDto reservationDto = new ReservationDto();
		reservationDto.setActionType("123");
		System.out.println(objectParseMap(reservationDto));
		
		m1.put("action", "123");
		m2.put("m1", "m1");
		m2.put("m2", "m2");
		m2.put("m3", "m3");
		m2.put("m4", "m4");
		m1.put("data", m2);
		System.out.println(JSON.toJSON(m1));

		m1.put("action", "123");
		m1.put("m1", "m1");
		m1.put("m2", "m2");
		m1.put("m3", "m3");
		m1.put("m4", "m4");
		m1.remove("data");
		System.out.println(JSON.toJSON(m1));
		
	}
}
